/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xuidemo.botnavigation;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;

import com.xuexiang.xuidemo.util.DisplayUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 底部导航栏的封装，第一个泛型就是底部导航栏的条目，第二个泛型就是每个条目的数据
 *
 * @since 2021-03-22
 */
public class BottomNavigationBar extends StackLayout implements IbarLayout<BottomBar, BottomBarInfo<?>> {
    private static final int ID_TAB_BOTTOM = 0XFF;
    private static final int anInt50 = 50;
    private static final int anInt223 = 223;
    private static final int anInt224 = 224;
    private static final int anInt225 = 225;
    private static final int anInt255 = 255;
    private static final float anlfloat = 0.5f;
    private BottomBar bottomBar = null;
    /**
     * 事件监听的集合
     */
    private List<OnBarSelectedListener<BottomBarInfo<?>>> tabSelectedListeners = new ArrayList<>();
    /**
     * 当前选中的条目
     */
    private BottomBarInfo<?> selectedInfo;
    /**
     * 底部导航栏的透明度
     */
    private float barBottomAlpha = 1;
    /**
     * 底部导航栏的高度
     */
    private float barBottomHeight = anInt50;
    /**
     * 底部导航栏线条的高度
     */
    private float barBottomLineHeight = anlfloat;
    /**
     * 底部导航栏线条的颜色
     */
    private RgbColor barBottomLineColor = new RgbColor(anInt223, anInt224, anInt225);
    /**
     * 所有的tab
     */
    private List<BottomBarInfo<?>> infoList;

    /**
     * 构造方法
     *
     * @param context 上下文
     */
    public BottomNavigationBar(Context context) {
        this(context, null);
    }

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param attrSet 样式
     */
    public BottomNavigationBar(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    /**
     * 构造方法
     *
     * @param context 上下文
     * @param attrSet 样式
     * @param styleName name
     */
    public BottomNavigationBar(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
    }

    /**
     * 根据数据查找条目
     *
     * @param info 条目的数据
     * @return 条目
     */
    @Override
    public BottomBar findBar(BottomBarInfo<?> info) {
        ComponentContainer componentContainer = (ComponentContainer) findComponentById(ID_TAB_BOTTOM);
        for (int i = 0; i < componentContainer.getChildCount(); i++) {
            Component component = componentContainer.getComponentAt(i);
            if (component instanceof BottomBar) {
                BottomBar bar = (BottomBar) component;
                if (bar.getTabInfo() == info) {
                    return bar;
                }
            }
        }
        return bottomBar;
    }

    public void setBottomBar(BottomBar bottomBar) {
        this.bottomBar = bottomBar;
    }

    /**
     * 添加监听
     *
     * @param listener 监听
     */
    @Override
    public void addBarSelectedChangeListener(OnBarSelectedListener<BottomBarInfo<?>> listener) {
        tabSelectedListeners.add(listener);
    }

    /**
     * 默认选中的条目
     *
     * @param defaultInfo 默认选中条目的信息
     */
    @Override
    public void defaultSelected(BottomBarInfo<?> defaultInfo) {
        onSelected(defaultInfo);
    }

    /**
     * 初始化所有的条目
     *
     * @param infos 所有条目的信息
     */
    @Override
    public void initInfo(List<BottomBarInfo<?>> infos) {
        if (infos == null || infos.isEmpty()) {
            return;
        }
        this.infoList = infos;
        removeComponent(); // 移除之前已经添加的组件，防止重复添加
        selectedInfo = null;
        addBackground(); // 添加背景
        addBottomBar(); // 添加条目
        addBottomLine(); // 添加线条
    }

    /**
     * 添加线条
     */
    private void addBottomLine() {
        Component line = new Component(getContext());
        ShapeElement element = new ShapeElement();
        element.setShape(ShapeElement.RECTANGLE);
        element.setRgbColor(barBottomLineColor);
        line.setBackground(element);
        LayoutConfig config = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            DisplayUtils.vp2px(getContext(), barBottomLineHeight));
        config.alignment = LayoutAlignment.BOTTOM;
        config.setMarginBottom(DisplayUtils.vp2px(getContext(), barBottomHeight - barBottomLineHeight));
        line.setAlpha(barBottomAlpha);
        addComponent(line, config);
    }

    /**
     * 添加条目
     */
    private void addBottomBar() {
        int width = DisplayUtils.getDisplayWidthInPx(getContext()) / infoList.size(); // 每个条目的宽度就是屏幕宽度除以条目的总个数
        int height = DisplayUtils.vp2px(getContext(), barBottomHeight); // 高度是固定的值，这里需要做屏幕适配，将vp转换成像素
        StackLayout stackLayout = new StackLayout(getContext());
        stackLayout.setId(ID_TAB_BOTTOM);
        for (int i = 0; i < infoList.size(); i++) {
            BottomBarInfo<?> info = infoList.get(i);
            LayoutConfig config = new LayoutConfig(width, height); // 创建布局配置对象
            config.alignment = LayoutAlignment.BOTTOM; // 设置底部对齐
            config.setMarginLeft(i * width); // 设置左边距
            BottomBar bar = new BottomBar(getContext());
            tabSelectedListeners.add(bar);
            bar.setBarInfo(info); // 初始化每个条目
            stackLayout.addComponent(bar, config); // 添加条目
            bar.setClickedListener(component -> onSelected(info)); // 设置点击事件
        }
        LayoutConfig layoutConfig = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_CONTENT);
        layoutConfig.alignment = LayoutAlignment.BOTTOM;
        addComponent(stackLayout, layoutConfig);
    }

    /**
     * 选择指定item
     *
     * @param index item 的索引
     */
    public void onSelected(int index) {
        if (infoList.size() > index) {
            onSelected(infoList.get(index));
        }
    }

    /**
     * 点击条目后给外界回调
     *
     * @param nextInfo 点击后需要选中的条目
     */
    private void onSelected(BottomBarInfo<?> nextInfo) {
        for (OnBarSelectedListener<BottomBarInfo<?>> listener : tabSelectedListeners) {
            listener.onBarSelectedChange(infoList.indexOf(nextInfo), selectedInfo, nextInfo);
        }
        if (nextInfo.tabType == BottomBarInfo.BarType.IMAGE_TEXT) {
            selectedInfo = nextInfo;
        }
    }

    /**
     * 添加背景
     */
    private void addBackground() {
        Component component = new Component(getContext());
        ShapeElement element = new ShapeElement();
        element.setShape(ShapeElement.RECTANGLE);
        RgbColor rgbColor = new RgbColor(anInt255, anInt255, anInt255);
        element.setRgbColor(rgbColor);
        component.setBackground(element);
        component.setAlpha(barBottomAlpha);
        LayoutConfig config = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            DisplayUtils.vp2px(getContext(), barBottomHeight));
        config.alignment = LayoutAlignment.BOTTOM;
        addComponent(component, config);
    }

    /**
     * 移除之前已经添加的组件，防止重复添加
     */
    private void removeComponent() {
        for (int i = getChildCount() - 1; i > 0; i--) {
            removeComponentAt(i);
        }
        tabSelectedListeners.removeIf(listener ->
            listener instanceof BottomBar);
    }

    /**
     * 设置底部导航栏的透明度
     *
     * @param barBottomAlpha 底部导航栏的透明度
     */
    public void setBarBottomAlpha(float barBottomAlpha) {
        this.barBottomAlpha = barBottomAlpha;
    }

    /**
     * 设置底部导航栏的高度
     *
     * @param barBottomHeight 底部导航栏的高度
     */
    public void setBarBottomHeight(float barBottomHeight) {
        this.barBottomHeight = barBottomHeight;
    }

    /**
     * 设置底部导航栏线条的高度
     *
     * @param barBottomLineHeight 底部导航栏线条的高度
     */
    public void setBarBottomLineHeight(float barBottomLineHeight) {
        this.barBottomLineHeight = barBottomLineHeight;
    }

    /**
     * 设置底部导航栏线条的颜色
     *
     * @param barBottomLineColor 底部导航栏线条的颜色
     */
    public void setBarBottomLineColor(RgbColor barBottomLineColor) {
        this.barBottomLineColor = barBottomLineColor;
    }
}
